---
title: PdfAPI.Client overview
summary: What the client wraps, who consumes it, and the capabilities it exposes.
status: draft
owner: SAIF Doc Gen
last_reviewed: 2026-09-17
---

# PdfAPI.Client overview

`PdfAPI.Client` gives consumers a single typed entry point, `PdfClient : IPdfClient`, for both calling the `PdfAPI` REST API and performing local, in-process PDF operations that never leave the caller's machine.

## Purpose
- Wrap five `PdfAPI` endpoints (document conversion, merge, PDF/A validation, and tracking-status
  lookup) behind a typed C# interface so consumers do not hand-roll HTTP calls.
- Ship six local PDF operations (version, page count, PDF validity, form-field detection and
  flattening, and page-range extraction) that execute entirely in the consumer's process against the shared `PdfAPI.Core` contracts and services assembly, requiring no API availability.

## What it wraps

`PdfClient` is a thin, hand-written wrapper over `SAIF.Web.API.Clients.JsonHttpClient` for its five remote members. It composes a relative URL, issues one call through `PostJson<T>` (four call sites) or `GetResult<T>` (one call site), and returns a contract type from `PdfAPI.Core`.

| Attribute | Value |
| --- | --- |
| Wrapped API | `PdfAPI` |
| API documentation | [PdfAPI](../../apis/pdfapi/index.md) |
| Base URI | `<url>` (caller-supplied, trailing slash trimmed) + `v1/` |
| Transport | JSON over HTTP or HTTPS — the scheme is whatever the caller-supplied base URI specifies; `PdfClient` does not enforce or upgrade to HTTPS |
| Contracts assembly | `PdfAPI.Core` |

## Consumers

Consumers visible in this repository. No external NuGet-feed consumer inventory was performed for this run.

| Consumer | Type | How it is consumed | Evidence |
| --- | --- | --- | --- |
| `PdfApiClientTester` | Console (secondary entry point; not documented by this run) | Direct `new PdfClient(new ClientInfo(), url)`, held as `IPdfClient` | `PdfApiClientTester\PdfApiClientTester\PdfTester.cs` lines 3, 16, 20–23 |
| `PdfAPI.Client.Tests` (`PdfClientTests`, `FormFieldTests`) | MSTest (excluded from documentation) | Direct `new PdfClient(new ClientInfo(), url)` | `PdfAPI.Client.Tests\PdfClientTests.cs` lines 30–38 |
| `PdfAPI.Tests` (`ClientTest`) | MSTest (excluded); stale construction that matches no current constructor | `new PdfAPI.Client.PdfClient(_envSvc)` | `PdfAPI.Tests\Client\ClientTest.cs` lines 20–27 |

No dependency-injection registration of `IPdfClient` was found in any consumer observed in scope — every consumer constructs `PdfClient` directly with `new`.

<!-- Consuming a client is not producing one. -->

## Capability summary

| Capability | Client member | Remote | Description |
| --- | --- | --- | --- |
| Convert a request-shaped document | `Convert(ConvertRequest)` | Yes | Posts a `ConvertRequest` body to `v1/convert` |
| Convert a file-shaped document | `Convert(byte[], string, PdfFormat)` | Yes | Posts raw bytes to `v1/convert/{fileExtension}` with an optional output `format` |
| Merge documents | `Merge(MergeRequest)` | Yes | Posts a `MergeRequest` body to `v1/merge` |
| Validate PDF/A conformance | `IsPdfa(byte[])` | Yes | Posts PDF bytes to `v1/info/validate/pdfa` (concrete class only — not on `IPdfClient`) |
| Check tracking status | `Track(long)` | Yes | Reads `v1/info/track/{trackingId}` via `GetResult<T>` (concrete class only — not on `IPdfClient`) |
| Read the PDF version | `Version(byte[])` | No | Local — delegates to `PdfClientService.Version` |
| Count pages | `Pages(byte[])` | No | Local — delegates to `PdfClientService.GetPageCount` |
| Validate is-PDF | `IsPdf(byte[])` | No | Local — delegates to `PdfClientService.IsPdf` |
| Detect form fields | `HasFormFields(byte[])` | No | Local — delegates to `PdfClientService.HasFormFields` |
| Flatten form fields | `Flatten(byte[])` | No | Local — delegates to `PdfClientService.Flatten` |
| Extract a page range | `Extract(DocumentRange)` | No | Local — delegates to `PdfClientService.ExtractPages` |

## Local (non-HTTP) capabilities

Six of the eleven public members issue no HTTP call. All six are one-line delegations to the static `PdfAPI.Core.PdfClientService`, which ships inside the client package, so these members execute entirely in the consumer's process using the consumer's own `iTextSharp` dependency.

| Member | Delegates to | Why it is local |
| --- | --- | --- |
| `Version(byte[])` | `PdfClientService.Version` | Regex-matches the `%PDF-` header in-process; no network |
| `Pages(byte[])` | `PdfClientService.GetPageCount` | Counts `/Type /Page` occurrences in-process |
| `IsPdf(byte[])` | `PdfClientService.IsPdf` | Magic-byte / header check in-process |
| `HasFormFields(byte[])` | `PdfClientService.HasFormFields` | Opens the bytes with `iTextSharp.text.pdf.PdfReader` in-process |
| `Flatten(byte[])` | `PdfClientService.Flatten` | Re-writes the bytes with `PdfStamper` in-process |
| `Extract(DocumentRange)` | `PdfClientService.ExtractPages` | Copies page ranges with `PdfCopy` in-process |

These six members duplicate functionality the API also exposes (`v1/info/validate`, `v1/info/version`, `v1/info/pages/count`, `v1/info/fields/exist`, `v1/info/fields/flatten`, `v1/extract`) — the API's own `PdfService` calls the same `PdfClientService` statics — but a consumer calling the client always takes the local path and never reaches the service.

## Related documentation
- [Client index](index.md)
- [Architecture](architecture.md)
- [Package](package.md)
- [Client reference](reference.md)
- [Endpoint map](endpoint-map.md)
- [Consumption](consumption.md)
- [Contracts](contracts.md)
- [Dependencies](dependencies.md)
- [Business rules](business-rules.md)
- [Tech debt](tech-debt.md)

## Sources
- `PdfAPI.Client\PdfClient.cs`
- `PdfAPI.Client\IPdfClient.cs`
- `PdfAPI.Core\Services\PdfClientService.cs`
- `PdfAPI\Services\PdfService.cs`
- `PdfApiClientTester\PdfApiClientTester\PdfTester.cs`
- `PdfAPI.Client.Tests\PdfClientTests.cs`
- `PdfAPI.Client.Tests\FormFieldTests.cs`
- `PdfAPI.Tests\Client\ClientTest.cs`
